''' Created on 19/04/2010 @author: Mar'''
import time
from ThreadCPU import ThreadCPU

class CPU:
    #===========================================================================
    # Define el comportamiento de la CPU.
    #===========================================================================
    def __init__(self, rQueue, aResourceManager,anOutputQueue,aScheduler):
        self.isFree = True
        self.readyQueue = rQueue
        self.resourceManager = aResourceManager
        self.outputQueue = anOutputQueue
        self.theScheduler = aScheduler
      
        self.quantum = 0
        self.quantumRemaining = self.quantum
        self.quantumPolicy = False

        self.setQuantumPolicy()
        self.cpuThread = ThreadCPU(self,aScheduler)
        self.cpuThread.setDaemon(True)
        self.cpuThread.start()
        self.setQuantumPolicy()
        self.setQuantum()
        self.refreshQuantum()
        
    def getFreedom(self):
        return self.isFree
    
    def setFreedom(self, x):
        self.isFree = x
    
    def setQuantumPolicy(self):
        #=======================================================================
        # Setear si el tipo de planificador tiene que usar quantum.
        #=======================================================================
        self.quantumPolicy = self.theScheduler.isQuantum()
    
    def setQuantum(self):
        #=======================================================================
        # Setear el quantum en caso de que el planificador sea Round Robin.
        #=======================================================================
        self.quantum = self.theScheduler.getQuantum()
        self.quantumRemaining = self.theScheduler.getQuantum() 
            
    def refreshQuantum(self):
        self.quantumRemaining = self.quantum
        
    def getQuantumPolicy(self):
        return self.quantumPolicy
    
    
        
    def getQuantumRemaining(self):
        return self.quantumRemaining
    
    def executePCB2(self, aPCB):
        self.setFreedom(False)
        wentToIO = False
        executedInstructions = 0 
        while(executedInstructions < aPCB.getInstToExectute()): 
            inst = aPCB.getCurrentInstruction()
            if (inst.isFork()):
                prog = inst.getProgram()
                pcbNew = prog.toPCB()
                pcbNew.setParent(aPCB)
                self.theScheduler.addPCB(pcbNew)
                self.theScheduler.sendToSleep(aPCB)
                aPCB.advance()
                break
            elif (inst.isCPU()):
                self.execute(inst)
                aPCB.advance()
            else:
                self.sendToIO(aPCB)
                wentToIO = True
                break 
            executedInstructions = executedInstructions + 1
        if (len(aPCB.program.instructions) == aPCB.getPC()):
            if(not(aPCB.isChild)):
                aPCB.toFinished() 
            else:
                y = aPCB.getParent()
                self.theScheduler.sendDadToReady(y)
        else:
            if(not(wentToIO)):
                self.readyQueue.put(aPCB) 
        self.setFreedom(True)
   
    def executePCB(self, aPCB):
        self.setFreedom(False)
        wentToIO = False
        while (aPCB.getPC() < len(aPCB.program.instructions)): 
            inst = aPCB.getCurrentInstruction()
            if (inst.isFork()):
                prog = inst.getProgram()
                pcbNew = prog.toPCB()
                pcbNew.setParent(aPCB)
                pcbNew.setChild()
                self.theScheduler.addPCB(pcbNew)
                self.theScheduler.sendToSleep(aPCB)
                aPCB.advance()
                break
            elif (inst.isCPU()): 
                self.execute(inst)
                aPCB.advance()
            else:
                self.sendToIO(aPCB)
                wentToIO = True
                break
        if (len(aPCB.program.instructions) == aPCB.getPC()):
            if(not(aPCB.isChild)):
                aPCB.toFinished() 
            else:
                y = aPCB.getParent()
                self.theScheduler.sendDadToReady(y)
        else:
            if(not(wentToIO)):
                self.readyQueue.put(aPCB)
           
        self.setFreedom(True)            
    
    
    def execute(self,anInst):
        print(anInst.getWord())
        self.outputQueue.put((anInst.getWord(),anInst.getTime()))
        time.sleep(anInst.getTime())  
        
        
    def killPCB(self, aPCB):
        self.readyQueue.get()
       
    def sendToIO(self, aPCB):
        self.resourceManager.distribute(aPCB)    


    
    
        
    
        